﻿using System;
using System.Collections.Generic;
using System.Text;
using OWLServerQL.dominio;
using Antlr.Runtime;
using OWLServer.owl.tipos;
using OWLServer.owl.conversores;
using System.IO;

namespace OWLServerQL
{
    /// <summary>
    /// Clase que se encarga de gestionar las consultas del OwlServerQL
    /// </summary>
    public class OwlServerQL : IfzOWLServerQL
    {
        // Constantes
        private const string ERROR_ONTONOGIA_NO_EXISTE = "La ontología \"{0}\" no existe en el sistema.";
        private const string ERROR_NO_EXISTEN_INIVIDUOS = "No existe individuos para esa consulta.";
        private const string ERROR_NO_EXISTEN_INIVIDUOS_ONTOLOGIA = "La ontología \"{0}\" no tiene individuos.";

        /// <summary>
        /// Nos devuelve la lista de Individus del resultado de la consulta
        /// </summary>
        /// <param name="consultaOwlServerQL">Consulta OwlServerQL</param>
        /// <returns>Lista de Individus del resultado de la consulta</returns>
        public List<Individuo> conversorOwlServerQLToIndividuos(String consultaOwlServerQL)
        {
            GestorOntologias gestor = new GestorOntologias();

            Consulta consulta = obtenerConsultaOwlServerQL(consultaOwlServerQL);

            return conversorOwlServerQLToIndividuos(consulta);
        }

        /// <summary>
        /// Nos devuelve la lista de Individus del resultado de la consulta
        /// </summary>
        /// <param name="consulta">Consulta OwlServerQL</param>
        /// <returns>Lista de Individus del resultado de la consulta</returns>
        public List<Individuo> conversorOwlServerQLToIndividuos(Consulta consulta)
        {
            List<Individuo> resultado = null;
            GestorOntologias gestor = new GestorOntologias();

            if (consulta.Ontologia != null && consulta.Cuerpo != null)
            {
                Ontologia ontologia = gestor.getOntologiaEspacioNombrePrincipal(consulta.Ontologia, true);
                if (ontologia != null)
                {
                    List<Individuo> individuosOntologia = new List<Individuo>(ontologia.Individuos);
                    if (individuosOntologia.Count > 0)
                    {
                        resultado = consulta.Cuerpo.owlServerQLToIndividuos(consulta.Cuerpo.TipoElemento, individuosOntologia);
                        if (resultado.Count == 0)
                        {
                            consulta.addError(ERROR_NO_EXISTEN_INIVIDUOS);
                        }
                    }
                    else
                    {
                        consulta.addError(string.Format(ERROR_NO_EXISTEN_INIVIDUOS_ONTOLOGIA, consulta.Ontologia));
                    }
                }
                else
                {
                    consulta.addError(string.Format(ERROR_ONTONOGIA_NO_EXISTE, consulta.Ontologia));
                }
            }

            return resultado;
        }

        /// <summary>
        /// Nos devuelve la lista de Individus del resultado de la consulta
        /// </summary>
        /// <param name="consultaOwlServerQL">Consulta OwlServerQL</param>
        /// <returns>XML del resultado de la consulta</returns>
        public string conversorOwlServerQLToXML(String consultaOwlServerQL)
        {
            StringBuilder xml = new StringBuilder();
            // Recuperamos al consulta
            Consulta consulta = obtenerConsultaOwlServerQL(consultaOwlServerQL);
            // Obtenemos la lista de individuos
            List<Individuo> individuos = conversorOwlServerQLToIndividuos(consulta);
            // Creamos el resultado
            OWLServerQL.xml.ResultadoConsultaQWLServerQL resultadoConsultaQWLServerQL = componerResultadoConsulta(consultaOwlServerQL, consulta, individuos);

            // Serializamos el resultado para transformarlo a XML
            StringWriter stringWriter = new StringWriter(xml);
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(resultadoConsultaQWLServerQL.GetType());
            x.Serialize(stringWriter, resultadoConsultaQWLServerQL);

            return xml.ToString();
        }

        /// <summary>
        /// Compone el resultado de la consulta para devolverlo.
        /// </summary>
        /// <param name="consultaOwlServerQL">Cadena de la consulta OwlServerQL</param>
        /// <param name="consulta">Objeto que representa la consulta</param>
        /// <param name="individuos">Lista de individuos que complen la consulta</param>
        /// <returns>Resultado de la Consulta QWLServerQL</returns>
        private OWLServerQL.xml.ResultadoConsultaQWLServerQL componerResultadoConsulta(String consultaOwlServerQL, Consulta consulta, List<Individuo> individuos)
        {
            OWLServerQL.xml.ResultadoConsultaQWLServerQL resultadoConsultaQWLServerQL = new OWLServerQL.xml.ResultadoConsultaQWLServerQL();

            // Si hemos encontrado individuos los insertamos en el XML
            if (individuos != null)
            {
                // Contruimos el XML
                List<OWLServerQL.xml.Individuo> individuosXML = new List<xml.Individuo>();

                foreach (Individuo indi in individuos)
                {
                    individuosXML.Add(new xml.Individuo(indi));
                }

                resultadoConsultaQWLServerQL.encontrados = individuos.Count;
                resultadoConsultaQWLServerQL.resultado = individuosXML;
            }
            // Componemos las partes conjuntas del XML
            resultadoConsultaQWLServerQL.consulta = consultaOwlServerQL;
            resultadoConsultaQWLServerQL.addErroresLexiscos(consulta.ErroresLexico);
            resultadoConsultaQWLServerQL.addErroresSemanticos(consulta.ErroresSemanticos);
            resultadoConsultaQWLServerQL.addErrores(consulta.Errores);

            return resultadoConsultaQWLServerQL;
        }

        /// <summary>
        /// Obtiene la consulta de OwlServerQL
        /// </summary>
        /// <param name="consultaOwlServerQL">Consulta OwlServerQL</param>
        /// <returns>Consulta OwlServerQL</returns>
        private Consulta obtenerConsultaOwlServerQL(String consultaOwlServerQL)
        {
            Consulta consulta = null;

            // Construimos el motor Lexico/Semantico
            ANTLRStringStream input = new ANTLRStringStream(consultaOwlServerQL);
            OwlServerQLLexer lexer = new OwlServerQLLexer(input);
            CommonTokenStream tokens = new CommonTokenStream(lexer);
            OwlServerQLParser parser = new OwlServerQLParser(tokens);

            // Ejecutamos la consulta OwlServerQL
            try
            {
                parser.inicio_consulta();
            }
            catch
            {

            }

            consulta = parser.ConsultaFinal;

            // Insertamos los errores si hay
            if (lexer.NumErrors > 0 || parser.NumErrors > 0)
            {
                consulta = new Consulta(null, null);
            }
            consulta.ErroresLexico = lexer.Errores;
            consulta.ErroresSemanticos = parser.Errores;

            return consulta;
        }
    }
}
